package com.ruoyi.dev.service.impl;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.*;

import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.dev.vo.DbField;
import com.ruoyi.system.mapper.SysMenuMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.dev.mapper.DevModelMapper;
import com.ruoyi.dev.domain.DevModel;
import com.ruoyi.dev.service.IDevModelService;

import javax.sql.DataSource;

/**
 * 数据模型Service业务层处理
 * 
 * @author yepanpan
 * @date 2025-01-21
 */
@Service
public class DevModelServiceImpl implements IDevModelService 
{
    private static final Logger log = LoggerFactory.getLogger(DevModelServiceImpl.class);
    public static final String CACHE_MAP = "dev_model";

    @Autowired
    private DevModelMapper devModelMapper;
    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    protected RedisCache redisCache;
    @Autowired
    protected DataSource dataSource;


    /**
     * 更新缓存
     * @return
     */
    @Override
    public int reCache(){
        redisCache.deleteObject(CACHE_MAP);
        return 0;
    }

    /**
     * 查询数据模型
     *
     * @param code 数据模型代码
     * @return 数据模型
     */
    @Override
    public DevModel selectDevModelDetail(String code){
        DevModel devModel = redisCache.getCacheObject(CACHE_MAP, code);
        if(devModel != null){
            return devModel;
        }

        devModel = devModelMapper.selectDevModelByCode(code);
        if(devModel == null){
            return null;
        }

        loadModelField(devModel);
        redisCache.setCacheObject(CACHE_MAP, code, devModel);
        return devModel;
    }

    /**
     * 同步模型字段
     *
     * @param devModel 模型主键
     * @return 模型字段
     */
    public int loadModelField(DevModel devModel)
    {
        try {
            Connection connection = dataSource.getConnection();
            DatabaseMetaData dm = connection.getMetaData();
            ResultSet rs = dm.getColumns(connection.getCatalog(), connection.getSchema(), devModel.getCode(), null);
            while (rs.next()) {
                DbField field = new DbField();
                field.setCode(rs.getString("COLUMN_NAME"));
                field.setName(StringUtils.isEmpty(rs.getString("REMARKS")) ? rs.getString("COLUMN_NAME") : rs.getString("REMARKS"));
                field.setType(rs.getString("TYPE_NAME"));
                field.setLengths(rs.getInt("COLUMN_SIZE"));
                field.setRequired(rs.getInt("NULLABLE") == 1 ? "N" : "Y");
                devModel.addField(field);
                log.debug(rs.getString("TABLE_NAME") + " - " + rs.getString("COLUMN_NAME") + " - " + rs.getString("COLUMN_NAME") + " - " + rs.getInt("NULLABLE"));
            }
            return 1;
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 查询数据模型
     *
     * @param id 数据模型主键
     * @return 数据模型
     */
    @Override
    public DevModel selectDevModelDetail(Long id){
        DevModel devModel = devModelMapper.selectDevModelById(id);
        if(devModel == null){
            return null;
        }

        DevModel cacheModel = redisCache.getCacheObject(CACHE_MAP, devModel.getCode());
        if(cacheModel != null){
            return cacheModel;
        }

        loadModelField(devModel);
        redisCache.setCacheObject(CACHE_MAP, devModel.getCode(), devModel);

        return devModel;
    }

    /**
     * 查询数据模型
     * 
     * @param id 数据模型主键
     * @return 数据模型
     */
    @Override
    public DevModel selectDevModelById(Long id)
    {
        return devModelMapper.selectDevModelById(id);
    }

    /**
     * 查询数据模型列表
     * 
     * @param devModel 数据模型
     * @return 数据模型
     */
    @Override
    public List<DevModel> selectDevModelList(DevModel devModel)
    {
        return devModelMapper.selectDevModelList(devModel);
    }

    /**
     * 新增数据模型
     * 
     * @param devModel 数据模型
     * @return 结果
     */
    @Override
    public int insertDevModel(DevModel devModel)
    {
        DevModel old = devModelMapper.selectDevModelByCode(devModel.getCode());
        if(old != null){
            throw new ServiceException("模型已存在:"+devModel.getCode());
        }
        devModel.setCreateTime(DateUtils.getNowDate());
        return devModelMapper.insertDevModel(devModel);
    }

    /**
     * 修改数据模型
     * 
     * @param devModel 数据模型
     * @return 结果
     */
    @Override
    public int updateDevModel(DevModel devModel)
    {
        reCache();
        DevModel old = devModelMapper.selectDevModelByCode(devModel.getCode());
        if(old != null && !old.getId().equals(devModel.getId())){
            throw new ServiceException("模型已存在:"+devModel.getCode());
        }

        devModel.setUpdateTime(DateUtils.getNowDate());
        return devModelMapper.updateDevModel(devModel);
    }

    /**
     * 批量删除数据模型
     * 
     * @param ids 需要删除的数据模型主键
     * @return 结果
     */
    @Override
    public int deleteDevModelByIds(Long[] ids)
    {
        return devModelMapper.deleteDevModelByIds(ids) + reCache();
    }

    /**
     * 删除数据模型信息
     * 
     * @param id 数据模型主键
     * @return 结果
     */
    @Override
    public int deleteDevModelById(Long id)
    {
        return devModelMapper.deleteDevModelById(id) + reCache();
    }

    /**
     * 新增模型菜单
     *
     * @param id 报表
     * @return 结果
     */
    public int addDevModelMenu(Long id){
        DevModel devModel = devModelMapper.selectDevModelById(id);
        if(devModel == null){
            throw new ServiceException("模型不存在");
        }

        //找默认的上级菜单，不存在就添加为顶级
        SysMenu topMenu = sysMenuMapper.selectMenuById(2044L);
        Long topId = topMenu == null? 0 : topMenu.getMenuId();

        //先判断菜单是否存在
        SysMenu menu = sysMenuMapper.checkMenuNameUnique(devModel.getName(), topId);
        if(menu != null){
            throw new ServiceException("菜单 \""+devModel.getName()+"\" 已经存在，不需要重复添加");
        }

        //保存新菜单
        menu = new SysMenu();
        menu.setParentId(topId);
        menu.setMenuName(devModel.getName());
        menu.setPath("app/"+devModel.getCode());
        menu.setPerms("app:run:"+devModel.getCode());
        menu.setQuery("{\"modelId\":\""+ devModel.getId()+"\"}");

        menu.setComponent("run/index");
        menu.setMenuType("C");
        menu.setCreateTime(new Date());
        menu.setCreateBy(SecurityUtils.getUsername());
        menu.setVisible("0");
        menu.setStatus("0");
        menu.setIsFrame("1");
        menu.setIsCache("0");
        menu.setOrderNum(9);
        return sysMenuMapper.insertMenu(menu);
    }
}
